# -*- encoding: utf-8 -*-

from odoo.addons.base_cw.public import merge_line

from odoo import models, fields, api, _
from odoo.addons import base_cw
from odoo.exceptions import UserError


class AccountReceive(models.Model):
    _name = 'account.receive'
    _inherit = ['account.receive', 'account.voucher.script']
    _description = u'收款单'

    script_line_ids = fields.One2many('account.voucher.script.line', 'ar_id', u'预切凭证明细')
    is_summary_generate_voucher = fields.Boolean(u'汇开凭证', default=False)
    cash_dialy_ids = fields.One2many('account.cash.dialy', 'receive_order_id', string='出纳日记账')

    def action_done(self):
        super(AccountReceive, self).action_done()
        for record in self:
            for receive_line in record.line_ids:
                # 创建汇票
                if receive_line.money_order:
                    if receive_line.amount <= receive_line.money_order.money_order_money:
                        receive_line.env['money.order.line'].create(dict(
                            drawer=receive_line.drawer.id,
                            transfer_partner_id=receive_line.transfer_partner_id.id,
                            partner_bank_id=receive_line.partner_bank_id.id,
                            payee=receive_line.payee.id,
                            transfer_money=receive_line.amount,
                            money_order_id=receive_line.money_order.id,
                            receive_date=fields.date.today(),
                            receive_line_id=receive_line.id,
                            receive_id=record.id,
                            received_voucher_id=record.voucher_id.id if record.voucher_id else False
                        ))
                    else:
                        raise UserError('收款金额必须小于或等于汇票金额')

    def action_confirm(self):
        for receive in self:
            receive.generate_account_voucher_script()
        super(AccountReceive, self).action_confirm()

    def action_cancel_confirm(self):
        for receive in self:
            receive.generate_cancel_voucher_script()
        super(AccountReceive, self).action_cancel_confirm()

    def action_cancel_done(self):
        super(AccountReceive, self).action_cancel_done()
        for record in self:
            if record.voucher_id.line_ids and record.voucher_id.state not in ('draft', 'cancel',):
                raise UserError(_(u'已经生成凭证内容，请先取消凭证明细再取消当前收款。'))
            money_order_line_ids = record.env['money.order.line'].search([('receive_id', '=', record.id)])
            for money_order_line in money_order_line_ids:
                money_order_line.unlink()
            # record.script_line_ids.unlink()

    def generate_account_voucher_script(self):
        self.ensure_one()
        self.generate_account_voucher_script_line()

    def generate_account_voucher(self):
        """继承创建凭证的方法，给凭证增加关联到付款单上的字段"""
        super(AccountReceive, self).generate_account_voucher()
        for record in self:
            if record.voucher_id:
                record.voucher_id.account_receive_id = record.id
                money_order_line_ids = record.env['money.order.line'].search([('receive_id', '=', record.id)])
                for money_order_line in money_order_line_ids:
                    money_order_line.write(dict(
                        received_voucher_id=record.voucher_id.id
                    ))

    def generate_cancel_voucher_script(self):
        '''
        取消生成的凭证
        :return:
        '''
        for receive in self:
            if receive.voucher_id and receive.voucher_id.state not in ('draft', 'cancel'):
                raise UserError(_(u'错误提示当前收款生成的凭证(%)已经确认，不能取消!' %self._name))
            if receive.voucher_id:
                receive.voucher_id.line_ids.unlink()
                receive.voucher_id = False

            receive.script_line_ids.unlink()

    @api.model
    def get_account(self, type_t):
        """
        获取会计科目
        :param type_t: 取值类型(advance 预收 prepaid 预付 receive 应收)
        :return:
        """

        config = self.env['account.voucher.template'].search([('code', '=', '01')], limit=1)
        if not config or not config.advance_account_id or not config.prepaid_account_id:
            raise UserError(_(u'请在财务{凭证模版}设定中 维护预收、预付会计科目!'))
        if type_t == 'advance':
            account_id = config.advance_account_id.id
        elif type_t == 'prepaid':
            account_id = config.prepaid_account_id.id
        elif type_t == 'receive':
            account_id = config.receivable_account_id.id
        else:
            pass
        return account_id

    def generate_account_voucher_script_line(self):
        """
        产生预切凭证明细
        :return:
        """

        for receive in self:
            receive.script_line_ids = False
            # 1.借方
            receives = receive.line_ids.filtered(lambda x: x.receive_category_id.is_receive)
            name = receives and receives[0].receive_category_id and receives[0].receive_category_id.name or False
            items = []
            d_items = []
            for x in receive.line_ids:
                d_item = dict(dc_type=x.dc_type,
                              account_id=x.account_id.id,
                              debit=x.amount if x.dc_type == 'D' else 0,
                              lc_debit=x.local_amount if x.dc_type == 'D' else 0,
                              credit=x.amount if x.dc_type == 'C' else 0,
                              lc_credit=x.local_amount if x.dc_type == 'C' else 0,
                              currency_id=x.master_id.currency_id and x.master_id.currency_id.id or False,
                              exchange_rate=x.master_id.currency_id and x.master_id.currency_id.rate or 1.0,
                              name=x.note or (name if not x.receive_category_id.is_receive else ''),
                              )
                if x.account_id.sub_account_type == 'has':

                    sub_account_lines_data = []
                    # 判断是否存在银行类型辅助核算
                    d_sub_category = x.account_id.subaccount_category_ids.filtered(lambda categ: categ.code == 'bank')
                    if d_sub_category:
                        line_data = {'category_id': d_sub_category[0].id,
                                     # 若科目中存在辅助核算，取辅助核算第一个，若没有取当前用户
                                     'sub_account_id': d_sub_category[0].sub_account_ids[0].id}
                        sub_account_lines_data.append((0, 0, line_data))
                    # for line in x.sub_account_lines:
                    #     line_data = {'category_id': line.category_id.id, 'sub_account_id': line.sub_account_id.id}
                    #     sub_account_lines_data.append((0, 0, line_data))

                    # if sub_account_lines_data:
                    #     for sub_account_line_data in sub_account_lines_data:
                    #         if sub_account_line_data[2] and sub_account_line_data[2].get(
                    #                 'sub_account_id') != receive.partner_id.id:
                    #             sub_account_lines_data.append(
                    #                 (0, 0, {'category_id': receive.partner_id.subaccount_category_id.id,
                    #                         'sub_account_id': receive.partner_id and receive.partner_id.id or False}))
                    d_item.update(dict(
                        sub_account_id=x.sub_account_id and x.sub_account_id.id or False,
                        sub_account_lines=sub_account_lines_data
                    ))
                d_items.append((0, 0, d_item))

            # 2.贷方
            c_items = []
            if receive.receive_type == 'B':  # '预收'
                account_id = self.get_account('advance')
                c_items=self.generate_account_voucher_script_line_c_items(name, x, receive, account_id, c_items)
            elif receive.receive_type == 'A' and len(receive.offset_line_ids) < 1:  # 未开票
                account_id = self.get_account('receive')
                c_items=self.generate_account_voucher_script_line_c_items(name, x, receive, account_id, c_items)
            else:
                for x in receive.offset_line_ids:#开票
                    c_item = dict(dc_type=x.dc_type,
                                  account_id=x.account_id.id,
                                  debit=x.amount,
                                  lc_debit=x.local_amount,
                                  currency_id=x.master_id.currency_id and x.master_id.currency_id.id or False,
                                  exchange_rate=x.master_id.currency_id and x.master_id.currency_id.rate or 1.0,
                                  name=receive.note or name
                                  )
                    if x.account_id.sub_account_type == 'has':
                        sub_account_lines_data = []
                        for line in x.sub_account_lines:
                            line_data = {'category_id': line.category_id.id, 'sub_account_id': line.sub_account_id.id}
                            sub_account_lines_data.append((0, 0, line_data))
                        if sub_account_lines_data:
                            for sub_account_line_data in sub_account_lines_data:
                                if sub_account_line_data[2] and sub_account_line_data[2].get(
                                        'sub_account_id') != receive.partner_id.id:
                                    sub_account_lines_data.append(
                                        (0, 0, {'category_id': receive.partner_id.subaccount_category_id.id,
                                                'sub_account_id': receive.partner_id and receive.partner_id.id or False}))
                        c_item.update(dict(
                            sub_account_id=x.sub_account_id and x.sub_account_id.id or False,
                            sub_account_lines=sub_account_lines_data
                        ))
                    c_items.append((0, 0, c_item))
            items += d_items + c_items
            items = merge_line(self, items)
            if items:
                receive.write(dict(script_line_ids=items))
            super(AccountReceive, self).generate_account_voucher_script_line()

    def generate_account_voucher_script_line_c_items(self, name, x, receive, account_id, c_items):
        """
        生成借方明细
        :param name:
        :param x: 付款明细行
        :param receive: 收款单
        :param account_id: 科目
        :param c_items: 借方列表
        :return:
        """
        c_item = dict(dc_type='C',
                      account_id=account_id,
                      credit=receive.receive_amount,
                      lc_credit=receive.local_receive_amount,
                      currency_id=receive.currency_id and receive.currency_id.id or False,
                      exchange_rate=receive.currency_id and receive.currency_id.rate or 1.0,
                      name=x.note or name
                      )
        c_account = self.env['cncw.account'].browse(account_id)
        if x.account_id.sub_account_type == 'has':
            sub_account_lines_data = []
            if c_account.sub_account_type == 'has':
                sub_account_lines_data = []
                # 判断是否存在客户类型辅助核算
                c_sub_category = c_account.subaccount_category_ids.filtered(
                    lambda categ: categ.code == 'customer')
                if c_sub_category:
                    line_data = {'category_id': c_sub_category[0].id,
                                 # 若科目中存在辅助核算，取辅助核算第一个，若没有取当前用户
                                 'sub_account_id': receive.partner_id and receive.partner_id.id or False}
                    sub_account_lines_data.append((0, 0, line_data))
        # if self.env['cncw.account'].browse(account_id).sub_account_type == 'has':
        #     sub_account_lines_data = []
        #     for line in self.env['cncw.account'].browse(account_id).subaccount_category_ids:
        #         line_data = {'category_id': line.id,
        #                      'sub_account_id': receive.partner_id and receive.partner_id.id or False}
        #         sub_account_lines_data.append((0, 0, line_data))
        #     if sub_account_lines_data:
        #         for sub_account_line_data in sub_account_lines_data:
        #             if sub_account_line_data[2] and sub_account_line_data[2].get(
        #                     'sub_account_id') != receive.partner_id.id:
        #                 sub_account_lines_data.append(
        #                     (0, 0, {'category_id': receive.partner_id.subaccount_category_id.id,
        #                             'sub_account_id': receive.partner_id and receive.partner_id.id or False}))
        #                 c_item.update(dict(
        #                     sub_account_id=x.sub_account_id and x.sub_account_id.id or False,
        #                     sub_account_lines=sub_account_lines_data
        #                 ))
        c_item.update(dict(
            sub_account_id=receive.partner_id and receive.partner_id.id or False,
            sub_account_lines=sub_account_lines_data
        ))
        c_items.append((0, 0, c_item))
        return c_items

    def _assert_balanced(self):
        if not self.ids:
            return True
        prec = self.env['decimal.precision'].precision_get('Amount')
        f_rule = '%.{}f'.format(max(5, prec))
        self._cr.execute("""
                SELECT ar_id
                  FROM account_voucher_script_line
                 WHERE ar_id in %s
              GROUP BY ar_id
                HAVING abs(sum(debit) - sum(credit)) > %s
            """, (tuple(self.ids),  float(f_rule % 10 ** (-max(5, prec)))))  # 默认取六位小数  10 ** (-max(5, prec))
        if len(self._cr.fetchall()) != 0:
            raise UserError(_(u"预切凭证借贷不平，请检查."))
        return True


class account_receive_offset_line(models.Model):
    _inherit = 'account.receive.offset.line'
    _description = u'收款单冲销明细'

    @api.depends('account_id')
    def _get_sub_account_ids(self):
        for record in self:
            account_obj = self.env['cncw.account']
            record.sub_account_ids = account_obj.get_sub_account_ids(record.account_id)

    sub_account_type = fields.Selection(base_cw.public.SUB_ACCOUNT_TYPE, u'辅助核算类型',
                                        related='account_id.sub_account_type', readonly=True)
    sub_account_ids = fields.Many2many('res.partner', compute='_get_sub_account_ids', string=u'可选辅助核算')


class AccountReceiveLine(models.Model):
    _inherit = 'account.receive.line'
    _description = u'收款单明细'

    @api.depends('account_id')
    def _get_sub_account_ids(self):
        for record in self:
            account_obj = self.env['cncw.account']
            record.sub_account_ids = account_obj.get_sub_account_ids(record.account_id)

    sub_account_type = fields.Selection(base_cw.public.SUB_ACCOUNT_TYPE, u'辅助核算类型',
                                        related='account_id.sub_account_type', readonly=True)
    sub_account_ids = fields.Many2many('res.partner', compute='_get_sub_account_ids', string=u'可选辅助核算')

    money_order = fields.Many2one(comodel_name='money.order', string='汇票')
    bill_date = fields.Date(string='出票日期', related='money_order.bill_date')
    bill_due_date = fields.Date(string='票据到期日', related='money_order.bill_due_date')
    overdue_days = fields.Integer(string='汇票到期天数', related='money_order.overdue_days')
    money_order_money = fields.Monetary(string='汇票金额', related='money_order.money_order_money')
    currency_id = fields.Many2one(comodel_name='res.currency', string='币别',
                                  default=lambda self: self.env.user.company_id.currency_id)

    drawer = fields.Many2one(comodel_name='res.partner', string='出票人')
    transfer_partner_id = fields.Many2one(comodel_name='res.partner', string='背书单位',
                                          defualt=lambda self: self.env.company.partner_id)
    partner_bank_id = fields.Many2one(comodel_name='res.partner.bank', string='出票银行')
    payee = fields.Many2one(comodel_name='res.partner', string='付款人', related='master_id.partner_id')
    # transfer_for_partner_id = fields.Many2one(comodel_name='res.partner', string='被背书单位')
    transfer_money = fields.Monetary(string='金额', currency_field='currency_id')

    def _compute_sub_account_lines(self):
        """在明细创建的时候给予默认的辅助核算"""
        pass
        # for record in self:
        #     if record.account_id and record.account_id.sub_account_type == 'has':
        #         sub_account_lines_data=[]
        #         for line in record.sub_account_lines:
        #             line_data = {'category_id': line.category_id.id, 'sub_account_id': line.sub_account_id.id}
        #             sub_account_lines_data.append((0, 0, line_data))
        #         # val = {'category_id': record.master_id.partner_id.subaccount_category_id.id,
        #         #        'sub_account_id': record.master_id.partner_id.id}
        #         record.sub_account_lines = [(0, 0, sub_account_lines_data)]

    def create(self, vals):
        res = super(AccountReceiveLine, self).create(vals)
        res._compute_sub_account_lines()
        return res

    def create_account_advance(self):
        """
        创建预收单
        :return:
        """
        for record in self:
            if record.master_id.state == 'done' and not record.advance_id and (record.master_id.receive_type == 'B' or (
                    record.master_id.receive_type == 'A' and record.account_id.ap_ar_type == '20' and record.dc_type == 'C')):
                sub_account_lines_data = []
                # if record.master_id.partner_id:
                #     line_data = {'category_id': record.master_id.partner_id.subaccount_category_id.id,
                #                  'sub_account_id': record.master_id.partner_id.id}
                #     sub_account_lines_data = [(0, 0, line_data)]
                for line in record.sub_account_lines:
                    line_data = {'category_id': line.category_id.id, 'sub_account_id': line.sub_account_id.id}
                    sub_account_lines_data.append((0, 0, line_data))

                item = dict(res_id=record.id,
                            date=record.master_id.date,
                            partner_id=record.master_id.partner_id.id,
                            currency_id=record.master_id.currency_id.id,
                            exchange_rate=record.master_id.exchange_rate,
                            tax_rate=record.master_id.tax_id.amount,
                            amount=record.amount,
                            total_amount=record.amount,
                            received_amount=0,
                            remaining_amount=record.amount,
                            lc_amount=record.local_amount,
                            lc_total_amount=record.local_amount,
                            lc_received_amount=0,
                            lc_remaining_amount=record.local_amount,
                            dc_type=record.dc_type,
                            note=record.note,
                            account_id=record.master_id.get_account(type_t='advance'),
                            org_account_id=record.account_id and record.account_id.id or False,
                            sub_account_id=record.master_id.partner_id and record.master_id.partner_id.id or False,
                            sub_account_lines=sub_account_lines_data,
                            offset_state='N')
                res = record.env['account.advance'].create(item)
                res.compute_remaining_amount()